import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QTextEdit, QVBoxLayout, QHBoxLayout, QMessageBox
from PyQt5.QtGui import QColor, QPainter, QTextCursor, QTextCharFormat, QTextBlockFormat, QIcon, QTextImageFormat
from PyQt5.QtCore import Qt, QTimer, QRect

import Sunny as SyNet
import json
import ctypes
import util
from pydash import get
Sunny = SyNet.SunnyNet()


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.is_expanded = True  # 窗口初始状态：展开
        self.is_sticky = False  # 窗口是否置顶的标志
        # 设置窗口的标题框和透明背景
        self.setWindowFlags(Qt.FramelessWindowHint)  # type: ignore
        # 使窗口背景透明
        self.setAttribute(Qt.WA_TranslucentBackground)  # type: ignore

        main_layout = QVBoxLayout()  # 创建总体布局
        button_layout = QHBoxLayout()  # 创建按钮布局（水平布局）
        # 创建退出按钮
        self.exit_button = QPushButton("退出")
        self.exit_button.setStyleSheet(
            "border:1px solid white;color:white;padding:5px;")
        self.exit_button.setFixedSize(100, 30)
        self.exit_button.clicked.connect(self.handle_exit)  # type: ignore
        button_layout.addWidget(self.exit_button)
        # 创建展开按钮
        self.toggle_button = QPushButton("隐藏")
        self.toggle_button .setStyleSheet(
            "border:1px solid white;color:white;padding:5px;")
        self.toggle_button .setFixedSize(100, 30)
        button_layout.addWidget(self.toggle_button)
        self.toggle_button.clicked.connect(self.toggle)  # 连接信号
        # 图片按钮作为置顶切换按钮
        self.sticky_button = QPushButton()
        self.sticky_button.setFixedSize(30, 30)  # 设置按钮大小
        self.sticky_button.setIcon(
            QIcon(util.get_resource_path("static/stick.png")))  # 设置图标，这里的路径需替换为您的图像路径
        self.sticky_button .setStyleSheet("border:none;")
        self.sticky_button.clicked.connect(self.toggle_sticky)
        button_layout.addWidget(self.sticky_button)

        # 将按钮布局添加到总体布局
        main_layout.addLayout(button_layout)
        # 创建文本框
        self.text_box = QTextEdit()
        self.text_box.setStyleSheet(
            "background: rgba(0, 0, 0, 0); color: white; border: none;font-size:18px;")
        self.text_box.setReadOnly(True)  # 只读
        main_layout.addWidget(self.text_box)

        # 设置布局
        self.setLayout(main_layout)

        # 设置窗口大小util.get_resource_path("static/logo.png")
        self.setGeometry(100, 100, 400, 900)
        self.setWindowTitle("弹幕获取工具V:Dow_process")
        self.setWindowIcon(QIcon(util.get_resource_path("static/logo.png")))
        # 定义定时器
        self.timer = QTimer()
        self.timer.timeout.connect(self.animate_height)
        # 控制动画的目标高度
        self.target_height = 900
        self.old_pos = None
        # 为 QTextEdit 添加鼠标事件
        self.text_box.mousePressEvent = self.mousePressEvent  # type: ignore # 重写鼠标按下事件
        self.text_box.mouseMoveEvent = self.mouseMoveEvent  # type: ignore # 重写鼠标移动事件

    def closeEvent(self, event):   # type: ignore
        reply = QMessageBox.question(
            self, '确认退出', '您确定要退出吗？', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()  # 允许关闭
        else:
            event.ignore()  # 取消关闭

    def toggle_sticky(self):
        if self.is_sticky:
            # type: ignore # 取消置顶
            self.setWindowFlags(self.windowFlags() & ~
                                Qt.WindowStaysOnTopHint)  # type: ignore
            # 默认图标 util.get_resource_path("static/stick.png")
            self.sticky_button.setIcon(
                QIcon(util.get_resource_path("static/stick.png")))
        else:
            # type: ignore # 设置为置顶
            self.setWindowFlags(self.windowFlags() |
                                Qt.WindowStaysOnTopHint)  # type: ignore
            self.sticky_button.setIcon(
                QIcon(util.get_resource_path("static/stick_1.png")))  # 置顶状态图标 util.get_resource_path("static/stick_1.png")
        self.is_sticky = not self.is_sticky
        self.show()  # 重新显示窗口以应用标志更改

    def handle_exit(self):
        self.close()  # 执行实际的关闭操作

    def toggle(self):
        if self.is_expanded:
            # 收起窗口
            self.target_height = 53
            self.toggle_button.setText("展开")  # 按钮文本改为“展开”
            self.timer.start(10)  # 启动定时器，调用动画函数
        else:
            # 展开窗口
            self.text_box.setFixedHeight(850)
            self.target_height = 900
            self.toggle_button.setText("隐藏")  # 按钮文本改为“隐藏”
            self.timer.start(10)  # 启动定时器，调用动画函数
        # 切换状态
        self.is_expanded = not self.is_expanded

    def animate_height(self):
        current_height = self.height()
        if current_height < self.target_height:
            # 展开动画
            new_height = min(current_height + 10, self.target_height)
            self.setFixedHeight(new_height)
        elif current_height > self.target_height:
            # 收起动画
            new_height = max(current_height - 10, self.target_height)
            self.setFixedHeight(new_height)
        # 判断是否达到目标高度并停止定时器
        if current_height == self.target_height:
            self.timer.stop()
            if self.is_expanded == False:
                self.text_box.setFixedHeight(0)

    def mousePressEvent(self, event):  # type: ignore
        if event.button() == Qt.LeftButton:  # type: ignore
            self.old_pos = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()

    def mouseMoveEvent(self, event):  # type: ignore
        if event.buttons() & Qt.LeftButton:  # type: ignore
            self.move(event.globalPos() - self.old_pos)
            event.accept()

    def paintEvent(self, event):  # type: ignore
        painter = QPainter(self)
        painter.setBrush(QColor(0, 0, 0, 160))  # 半透明黑色
        rounded_rect = QRect(0, 0, self.width(), self.height())  # 创建一个带圆角的矩形
        painter.drawRoundedRect(rounded_rect, 5, 5)  # 这里设置圆角半径为 5

    def add_message(self, message, color='white', image_path=None):
        """添加消息到文本框，并设置文本颜色"""
        cursor = self.text_box.textCursor()  # 获取光标
        cursor.movePosition(QTextCursor.End)  # 移动光标到文本框末尾
        # 创建文本格式
        text_format = QTextCharFormat()
        text_format.setForeground(QColor(color))  # 设置前景色
        cursor.insertText(message, text_format)  # 插入带格式的文本
        if image_path:
            image_format = QTextImageFormat()
            image_format.setName(image_path)  # 设置要插入的图像路径
            image_format.setWidth(20)  # 设置图像宽度
            image_format.setHeight(20)  # 设置图像高度
            cursor.insertImage(image_format)  # 插入图片
        # 创建块格式，以设置外边距
        block_format = QTextBlockFormat()
        block_format.setTopMargin(1)    # 设置上边距为1像素
        cursor.insertBlock(block_format)  # 插入带有外边距的块（换行）
        cursor.insertBlock()  # 插入换行
        # 保持滚动条在最底部
        self.text_box.moveCursor(QTextCursor.End)


app = QApplication(sys.argv)
window = MyWindow()


class Callback:
    def Tcp(SunnyContext, 来源地址, 远程地址, 消息类型, MessageId, 数据指针, 数据长度, 唯一ID, pid):  # type: ignore
        byte_array = SyNet.Tcp_取数据(数据指针, 数据长度)
        str_data = SyNet.PB转PbJSON(byte_array)
        if str_data is not None:
            json_data = json.loads(str_data)
            if json_data is not None:
                MessageAnalysis(json_data)

    def Ws(SunnyContext, 请求唯一ID, MessageId, 消息类型, 请求方式, 请求地址, pid, ws消息类型):  # type: ignore
        pass


def MessageAnalysis(json_data):  # 解析快手消息
    if json_data[0]['value'] == '310' and json_data[2]['Type'] == 'Object':
        弹幕消息 = util.KsMessage(json_data, 0)
        if 弹幕消息 is not None:
            msg = 弹幕消息['userName'] + " : " + 弹幕消息['context']  # type: ignore
            window.add_message(str(msg), '#ffe100')
            # send_all_msg_wrapper(str(弹幕消息))
    elif json_data[0]['value'] == '310' and json_data[2]['Type'] == 'StringRaw':
        json_data = util.base64ToPbJson(json_data[2]['value'])

        弹幕消息 = util.KsMessage(json_data, 1)
        if 弹幕消息 is not None:
            msg = 弹幕消息['userName'] + " : " + 弹幕消息['context']  # type: ignore
            window.add_message(str(msg), '#ffe100')
            # send_all_msg_wrapper(str(弹幕消息))

        for index, item in enumerate(json_data):  # type: ignore
            giftMsg = {
                "type": 1,  # 礼物消息
                "userName": None,
                "userId": None,
                "userSex": None,
                "giftId": None,  # 礼物ID
                "giftName": None,  # 礼物名字
                "giftNumber": None,  # 礼物数量
                "giftValue": None,  # 礼物总价值
                "giftType": None,  # 礼物类型 2048背包礼物 8192抽奖礼物 1正常礼物
            }
            namePath = get(json_data, f'[{index}].value.[1].value.[1]', None)
            giftMsg['userName'] = None if namePath is None else namePath['note'] if namePath['Type'] == 'StringRaw' else namePath['value']
            giftMsg['userSex'] = get(
                json_data, f'[{index}].value.[1].value.[2].value', None)
            giftMsg['userId'] = get(
                json_data, f'[{index}].value.[1].value.[0].value', None)

            if get(json_data, f'[{index}].value.[3].Type', None) == 'Varint' and get(json_data, f'[{index}].value.[9].value', None) == '300000':
                giftMsg['giftId'] = get(
                    json_data, f'[{index}].value.[3].value', None)
                giftMsg['giftNumber'] = get(
                    json_data, f'[{index}].value.[6].value', None)
                giftMsg['giftValue'] = get(
                    json_data, f'[{index}].value.[8].value', None)

                if giftMsg['giftValue'] is not None:
                    giftMsg['giftValue'] = int(giftMsg['giftValue']) - 1

                giftMsg['giftType'] = get(
                    json_data, f'[{index}].value.[14].value', None)

                if (giftMsg['giftId'] is not None and
                        giftMsg['giftNumber'] is not None and
                        giftMsg['giftValue'] is not None and
                        giftMsg['giftType'] is not None):
                    giftMsg['giftName'] = str(
                        util.giftIdToName(giftMsg['giftId']))

                    msg = (f"{giftMsg['userName']} : 送出 {giftMsg['giftName']} "
                           f"数量[{str(giftMsg['giftNumber'])}] | "
                           f"价值[{str(giftMsg['giftValue'])}]")  # type: ignore
                    window.add_message(str(msg), '#00ff08')


def 启动sunny():
    Sunny.绑定端口(2024)
    Sunny.绑定回调地址(None, Callback.Tcp, None, None)
    if not Sunny.启动():
        window.add_message('启动失败', 'red')
        print(Sunny.取错误())
    else:
        print("Sunny正在运行 0.0.0.0:2024")  # type: ignore
        if not Sunny.进程代理_加载驱动():
            window.add_message(
                '加载驱动失败(注意,需要管理员权限(请检查)win7请安装 KB3033929 补丁', 'red')
            window.add_message(
                '加载驱动失败(注意,需要管理员权限(请检查)win10/11请检查当前用户在Windows目录下SunnyFilter32.DLL,SunnyFilter64.DLL,SunnyFilter2.sys是否有控制权限', 'red')
        else:
            # 添加、删除 进程名、PID 会让目标进程断网一次
            Sunny.进程代理_添加进程名("kwailive.exe")
            window.add_message('启动成功~~~~', '#00ff08')


def foundWin():
    """创建一个win窗口"""
    window.show()
    # 添加示例消息
    window.add_message("欢迎使用快手弹幕获取工具！", 'white',
                       util.get_resource_path("static/logo.png"))
    # window.add_message("WebSocket服务端口 ws://localhost:8887")
    window.add_message("BUG以及其他问题联系V:Dow_process", '#ff6200')
    window.add_message("仅供用于学习测试,任何违法行为与作者无关", '#ff6200')

    启动sunny()
    sys.exit(app.exec_())


if __name__ == "__main__":
    if not util.is_admin():
        # 如果没有管理员权限，重新启动脚本并请求权限
        ctypes.windll.shell32.ShellExecuteW(
            None, "runas", sys.executable, " ".join(sys.argv), None, 1)
        sys.exit(0)  # 退出当前脚本
    foundWin()  # 创建一个win窗口
